package com.piece.blog.service;

import com.piece.admin.api.dto.SysUserDTO;
import com.piece.admin.model.TbSysUser;
import com.piece.admin.service.TbSysUserService;
import com.piece.blog.event.ArticlePostEvent;
import com.piece.blog.model.Article;
import com.piece.blog.model.ArticleInfo;
import com.piece.blog.repository.ArticleRepository;
import com.piece.core.elasticsearch.support.EsSearchUtil;
import com.piece.core.framework.enums.OptionType;
import com.piece.core.framework.enums.StatusType;
import com.piece.core.framework.enums.sql.SqlKey;
import com.piece.core.framework.exception.ServerException;
import com.piece.core.framework.support.bootstrap.DataTable;
import com.piece.core.framework.support.bootstrap.Order;
import com.piece.core.framework.support.bootstrap.QueryTable;
import com.piece.core.framework.support.convert.Convert;
import com.piece.core.framework.util.async.AsyncManager;
import com.piece.core.framework.util.basic.I18nUtil;
import com.piece.core.framework.util.collection.MapUtil;
import com.piece.core.framework.util.lock.LockUtil;
import com.piece.core.framework.util.string.JsonUtil;
import com.piece.core.framework.util.string.StringUtil;
import com.piece.core.jpa.repository.BaseService;
import com.piece.core.mongo.entity.MongoMessage;
import com.piece.core.mongo.service.MongoMessageService;
import com.piece.file.client.FileClientFactory;
import com.piece.file.model.TbSysFile;
import com.piece.file.service.TbSysFileService;
import com.piece.member.model.UmsMember;
import com.piece.member.service.UmsMemberService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.ListUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
public class ArticleService extends BaseService<Article, String> {

    public final String ARTICLE_KEY = "ARTICLE_OPERATE_";

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private ArticleRepository articleRepository;

    @Resource
    private ArticleInfoService articleInfoService;

    @Resource
    private ArticleTagService articleTagService;

    @Resource
    private MongoMessageService mongoMessageService;

    @Resource
    private TbSysUserService tbSysUserService;

    @Resource
    private UmsMemberService umsMemberService;

    @Resource
    private TbSysFileService tbSysFileService;

    @Autowired
    private FileClientFactory fileClientFactory;

    @PostConstruct
    public void initRepository() {
        setRepository(articleRepository);
    }

    /**
     * 保存、发布文章
     */
    public void post(Article article) {
        String content = null, html = null, thumbnail = null, tempStatus = null, tempOpen = null;
        // 处理摘要
//        if (StringUtil.isEmpty(article.getSummary()) && FrameWorkConstants.DELETED.equals(article.getCrypto())) {
//            article.setSummary(HtmlUtil.previewText(article.getContent(), 126));
//        }
        if (null == article.getArticleId()) {
            article = articleRepository.insert(article);
        } else {
            Article tempArticle = articleRepository.findById(article.getArticleId());
            if (null != tempArticle) {
                tempStatus = tempArticle.getStatus();
                tempOpen = tempArticle.getOpen();
                thumbnail = tempArticle.getThumbnail();
            }
            articleRepository.update(article);
        }

        if (StringUtil.isNotEmpty(article.getTags())) {
            articleTagService.batchUpdate(article.getTags(), article.getArticleId(), Convert.toLong(article.getCreateBy()));
        }

        String key = ARTICLE_KEY + article.getArticleId();
        AtomicInteger lock = LockUtil.getAtomicInteger(key);
        try {
            synchronized (lock) {
                String newContent = article.getContent();
                String newHtml = article.getHtml();
                String newThumbnail = article.getThumbnail();
                // 保存扩展
                ArticleInfo info = articleInfoService.findByArticle(article.getArticleId());
                boolean insert_ = false;
                if (null == info) {
                    insert_ = true;
                    info = new ArticleInfo();
                } else {
                    content = info.getContent();
                    html = info.getHtml();
                    if (StringUtil.isEmpty(newContent)) {
                        newContent = content;
                    }
                    if (StringUtil.isEmpty(newHtml)) {
                        newHtml = html;
                    }
                }
                info.setArticleId(article.getArticleId());
                info.setContent(newContent);
                info.setHtml(newHtml);
                if (insert_) {
                    articleInfoService.insert(info);
                } else {
                    articleInfoService.update(info);
                }

                if (!StringUtil.equalsWithEmpty(newThumbnail, thumbnail)) {
                    countResource(article.getArticleId(), Convert.toStrList(newThumbnail), Convert.toStrList(thumbnail));
                }
                countResource(article.getArticleId(), content, newContent);
                // 文章通知
                Article temp = article;
                if (null == tempStatus || null == tempOpen) {
                    if (StatusType.NORMAL.getCode().equals(article.getStatus())) {
                        // 新公开发布文章
                        onPushEvent(article, ArticlePostEvent.ACTION_PUBLISH);
                        // 创建索引
                        AsyncManager.getInstance().submit(new TimerTask() {
                            @Override
                            public void run() {
                                try {
                                    EsSearchUtil.getInstance().insert(temp);
                                } catch (Exception e) {
                                    log.error(e.getMessage());
                                }
                            }
                        });
                    }
                } else if (!tempStatus.equals(article.getStatus())) {
                    if (StatusType.NORMAL.getCode().equals(article.getStatus())) {
                        // 新公开发布文章
                        onPushEvent(article, ArticlePostEvent.ACTION_PUBLISH);
                        // 创建索引
                        AsyncManager.getInstance().submit(new TimerTask() {
                            @Override
                            public void run() {
                                try {
                                    EsSearchUtil.getInstance().insert(temp);
                                } catch (Exception e) {
                                    log.error(e.getMessage());
                                }
                            }
                        });
                    } else {
                        // 取消发布文章
                        onPushEvent(article, ArticlePostEvent.ACTION_DELETE);
                        // 删除索引
                        AsyncManager.getInstance().submit(new TimerTask() {
                            @Override
                            public void run() {
                                try {
                                    EsSearchUtil.getInstance().delete(temp.getArticleId().toString(), Article.class);
                                } catch (Exception e) {
                                    log.error(e.getMessage());
                                }
                            }
                        });
                    }
                } else if (tempStatus.equals(article.getStatus())) {
                    if (StatusType.NORMAL.getCode().equals(article.getStatus())) {
                        // 更新文章索引
                        onPushEvent(article, ArticlePostEvent.ACTION_UPDATE);
                        // 更新索引
                        AsyncManager.getInstance().submit(new TimerTask() {
                            @Override
                            public void run() {
                                try {
                                    EsSearchUtil.getInstance().update(temp);
                                } catch (Exception e) {
                                    log.error(e.getMessage());
                                }
                            }
                        });
                    }
                }
            }
        } catch (Exception e) {
            throw new ServerException(I18nUtil.message("blog.post.error"));
        } finally {
            LockUtil.releaseAtomicInteger(key);
        }
    }

    private void countResource(Long articleId, String originContent, String newContent) throws Exception {
        if (StringUtil.isEmpty(originContent)){
            originContent = "";
        }

        if (StringUtil.isEmpty(newContent)){
            newContent = "";
        }

        Set<String> exists = extractImageMd5(originContent);
        Set<String> news = extractImageMd5(newContent);

        List<String> adds = ListUtils.removeAll(news, exists);
        List<String> deletes = ListUtils.removeAll(exists, news);

        countResource(articleId, adds, deletes);
    }

    private void countResource(Long articleId, List<String> adds, List<String> deletes) throws Exception {
        if (adds.size() > 0) {
            List<TbSysFile> files = tbSysFileService.findByCondition(MapUtil.builder(new HashMap<String, Object>())
                    .put("Q_fileId_S_IN", adds).build());
            List<TbSysFile> prs = files.stream().map(file -> {
                if (StringUtil.isEmpty(file.getTable())) {
                    file.setTable(ArticleInfo.class.getSimpleName());
                    file.setBusinessId(Convert.toStr(articleId));
                }
                return file;
            }).collect(Collectors.toList());
            tbSysFileService.batchUpdate(prs);
        }

        if (deletes.size() > 0) {
            List<TbSysFile> files = tbSysFileService.findByCondition(MapUtil.builder(new HashMap<String, Object>())
                    .put("Q_fileId_S_IN", deletes).build());
            for (TbSysFile file : files) {
                tbSysFileService.delete(file.getFileId());
            }
        }
    }

    private Set<String> extractImageMd5(String text) {
        Pattern pattern = Pattern.compile("(?<=/public/file/download/)(.+?)(?=\\\")");
        Set<String> md5s = new HashSet<>();

        Matcher originMatcher = pattern.matcher(text);
        while (originMatcher.find()) {
            String key = originMatcher.group();
            md5s.add(key);
        }
        return md5s;
    }

    public int favor(Article article, long userId) {
        int result = 0;
        if (null != article) {
            String key = ARTICLE_KEY + article.getArticleId() + ArticlePostEvent.ACTION_FAVOR;
            AtomicInteger lock = LockUtil.getAtomicInteger(key);
            try {
                String favorSql = "select count(1) from blog_user_favor where article_id=? and user_id=?";
                int count = jdbcTemplate.queryForObject(favorSql, Integer.class, new Object[]{article.getArticleId(), userId});
                synchronized (lock) {
                    if (count > 0) {
                        favorSql = "delete from blog_user_favor where article_id=? and user_id=? ";
                        result = -1;
                    } else {
                        favorSql = "insert into blog_user_favor(article_id, user_id) values(?, ?)";
                        result = 1;
                        onPushEvent(article, ArticlePostEvent.ACTION_FAVOR);
                    }
                    article.setFavors(article.getFavors() + result);
                    update(article);
                    jdbcTemplate.update(favorSql, new Object[]{article.getArticleId(), userId});
                }
            } catch (Exception e) {
                throw new ServerException(I18nUtil.message("blog.favor.error"));
            } finally {
                LockUtil.releaseAtomicInteger(key);
            }
        }
        return result;
    }

    public boolean hasWatch(SysUserDTO watcher, long watchedId) {
        boolean result = false;
        if (null != watcher) {
            try {
                String watchSql = "select count(1) from blog_user_watch where watcher=? and watched=?";
                int count = jdbcTemplate.queryForObject(watchSql, Integer.class, new Object[]{watcher.getUserId(), watchedId});
                if (count > 0) {
                    result = true;
                }
            } catch (Exception e) {
                throw new ServerException(I18nUtil.message("blog.watcher.error"));
            }
        }
        return result;
    }

    public int watcher(SysUserDTO watcher, long watchedId) {
        int result = 0;
        if (null != watcher) {
            try {
                String watchSql = "select count(1) from blog_user_watch where watcher=? and watched=?";
                int count = jdbcTemplate.queryForObject(watchSql, Integer.class, new Object[]{watcher.getUserId(), watchedId});
                if (count > 0) {
                    watchSql = "delete from blog_user_watch where watcher=? and watched=? ";
                    result = -1;
                } else {
                    watchSql = "insert into blog_user_watch(watcher, watched) values(?, ?)";
                    result = 1;
                }
                jdbcTemplate.update(watchSql, new Object[]{watcher.getUserId(), watchedId});
            } catch (Exception e) {
                throw new ServerException(I18nUtil.message("blog.watcher.error"));
            }
        }
        return result;
    }

    public void onPushEvent(Article article, int action) {
        ArticlePostEvent event = new ArticlePostEvent(System.currentTimeMillis());
        event.setArticle(article);
        event.setAction(action);
        applicationContext.publishEvent(event);
    }

    public void publish(Long[] ids) {
        String sql = "update blog_article set status = ? where article_id in(?)";
        jdbcTemplate.update(sql, new Object[]{StatusType.NORMAL.getCode(), Arrays.asList(ids)});
    }

    /**
     * 删除记录
     */
    public void delete(Article article) {
        String key = ARTICLE_KEY + article.getArticleId();

        try {
            AtomicInteger lock = LockUtil.getAtomicInteger(key);
            synchronized (lock) {
                // 删除附件
                try {
                    tbSysFileService.deleteByTableAndBusinessList(ArticleInfo.class.getSimpleName(), Convert.toStrList(article.getArticleId() + ""));
                } catch (Exception e) {
                    log.error("删除文件失败", e);
                }
                // 删除文章详情
                jdbcTemplate.update("delete from blog_article_info where article_id = ?", new Object[]{article.getArticleId()});
                // 删除标签
                articleTagService.batchDelete(article.getArticleId());
                // 删除文章
                articleRepository.delete(article.getArticleId());
                // 文章删除通知
                onPushEvent(article, ArticlePostEvent.ACTION_DELETE);
                // 删除文章索引
                AsyncManager.getInstance().submit(new TimerTask() {
                    @Override
                    public void run() {
                        try {
                            EsSearchUtil.getInstance().delete(article.getArticleId().toString(), Article.class);
                        } catch (Exception e) {
                            log.error(e.getMessage());
                        }
                    }
                });
            }
        } finally {
            LockUtil.releaseAtomicInteger(key);
        }
    }

    public void setOtherInfo(Article article) {
        long createBy = Convert.toLong(article.getCreateBy());
        // 获取作者所有发布文章数量
        String sql = "select Article from Article where createBy = ?0 and status = ?1 and open = ?2";
        int userPosts = Convert.toInt(articleRepository.count(sql, new Object[]{createBy, StatusType.NORMAL.getCode(), StatusType.NORMAL.getCode()}, true), 0);
        article.setUserPosts(userPosts);
        sql = "select count(1) from blog_user_watch where watched = ?";
        int userWatchers = jdbcTemplate.queryForObject(sql, Integer.class, new Object[]{createBy});
        article.setUserWatchers(userWatchers);
        sql = "select count(1) from blog_user_favor where article_id in (select article_id from blog_article where create_by = ?)";
        int userFavors = jdbcTemplate.queryForObject(sql, Integer.class, new Object[]{createBy});
        article.setUserFavors(userFavors);
    }

    /**
     * 查询下一个序号
     */
    public int findNextIndex(String group) {
        if (StringUtil.isEmpty(group)) {
            String sql = "select ifnull(max(weight) + 1,1) from `article` where status != ?";
            return jdbcTemplate.queryForObject(sql, Integer.class, StatusType.DELETE.getCode());
        } else {
            String sql = "select ifnull(max(group_index) + 1,1) from `article` where group_name = ? and status != ?";
            return jdbcTemplate.queryForObject(sql, Integer.class, new Object[]{group, StatusType.DELETE.getCode()});
        }
    }

    /**
     * 查询最新或推荐的文章
     *
     * @param count    查询数量
     * @param featured 是否推荐
     * @param author   文章所属
     * @param login    当前登陆人
     */
    public List<Article> findByLatestOrFeatured(int count, boolean featured, SysUserDTO author, SysUserDTO login) {
        QueryTable query = new QueryTable();
        query.setStart(0);
        query.setLength(count);
        Map<String, Object> param = new HashMap<>();
        param.put("Q_open_S_EQ", StatusType.NORMAL.getCode());
        param.put("Q_status_S_EQ", StatusType.NORMAL.getCode());
        if (featured) {
            param.put("Q_featured_S_EQ", StatusType.NORMAL.getCode());
        }
        if (null != author) {
            param.put("Q_createBy_L_EQ", author.getUserId());
        }

        if (null == login) {
            param.put("Q_memberLevel_INT_EQ", StatusType.NORMAL.getCode());
        } else {
            UmsMember userMember = umsMemberService.findByUser(login.getUserId());
            Integer level = null == userMember ? 1 : Convert.toInt(userMember.getLevelId(), 1);
            if (null != level && 0 != level) {
                param.put("Q_memberLevel_INT_LE", level);
            }
        }
        query.setParams(param);
        List<Order> orders = generatorOrder(null);
        query.setOrder(orders);
        return articleRepository.findPage(query).getData();
    }

    /**
     * 查询发表的文章
     */
    public DataTable findPosts(int pageIndex, int pageSize, SysUserDTO author, SysUserDTO login) {
        QueryTable query = new QueryTable();
        query.setCurrentPage(pageIndex);
        query.setLength(pageSize);
        query.setStart((query.getCurrentPage() - 1) * query.getLength());
        Map<String, Object> param = new HashMap<>();
        if (null == login) {
            param.put("Q_open_S_EQ", StatusType.NORMAL.getCode());
            param.put("Q_memberLevel_INT_EQ", StatusType.NORMAL.getCode());
        } else if (login.getUserId() != author.getUserId()){
            param.put("Q_open_S_EQ", StatusType.NORMAL.getCode());
            UmsMember userMember = umsMemberService.findByUser(login.getUserId());
            Integer level = null == userMember ? 1 : Convert.toInt(userMember.getLevelId(), 1);
            if (null != level && 0 != level) {
                param.put("Q_memberLevel_INT_LE", level);
            }
        }
        param.put("Q_status_S_EQ", StatusType.NORMAL.getCode());
        param.put("Q_createBy_L_EQ", author.getUserId());
        query.setParams(param);
        List<Order> orders = generatorOrder(null);
        query.setOrder(orders);
        return articleRepository.findPage(query);
    }

    /**
     * 查询收藏的文章
     */
    public DataTable findFavors(int pageIndex, int pageSize, SysUserDTO author, SysUserDTO login) {
        QueryTable query = new QueryTable();
        query.setCurrentPage(pageIndex);
        query.setLength(pageSize);
        query.setStart((query.getCurrentPage() - 1) * query.getLength());

        String sql = "select * from blog_article where create_by in (select article_id from blog_user_favor where user_id = " + author.getUserId() + ") ";
        Map<String, Object> param = new HashMap<>();
        param.put("Q_open_S_EQ", StatusType.NORMAL.getCode());
        if (null == login) {
            param.put("Q_memberLevel_INT_EQ", StatusType.NORMAL.getCode());
        } else if (login.getUserId() != author.getUserId()) {
            UmsMember userMember = umsMemberService.findByUser(login.getUserId());
            Integer level = null == userMember ? 1 : Convert.toInt(userMember.getLevelId(), 1);
            if (null != level && 0 != level) {
                param.put("Q_memberLevel_INT_LE", level);
            }
        }
        param.put("Q_status_S_EQ", StatusType.NORMAL.getCode());

        query.setHql(sql);
        List<Order> orders = generatorOrder(null);
        query.setOrder(orders);
        return articleRepository.findPageBySql(query);
    }

    /**
     * 查询系列下的所有文章
     *
     * @param group    文章分组
     * @param author   文章作者
     * @param author   当前登陆人
     */
    public List<Article> findByGroup(String group, SysUserDTO author, SysUserDTO login) {
        QueryTable query = new QueryTable();
        query.setStart(0);
        query.setLength(0);
        Map<String, Object> param = new HashMap<>();
        param.put("Q_status_S_EQ", StatusType.NORMAL.getCode());
        param.put("Q_group_S_EQ", group);
        if (null != author) {
            param.put("Q_createBy_L_EQ", author.getUserId());
        }

        if (null == login) {
            param.put("Q_open_S_EQ", StatusType.NORMAL.getCode());
            param.put("Q_memberLevel_INT_EQ", StatusType.NORMAL.getCode());
        } else {
            UmsMember userMember = umsMemberService.findByUser(login.getUserId());
            Integer level = null == userMember ? 1 : Convert.toInt(userMember.getLevelId(), 1);
            if (null != level && 0 != level) {
                param.put("Q_memberLevel_INT_LE", level);
            }
        }
        query.setParams(param);
        List<Order> orders = generatorOrder(null);
        query.setOrder(orders);
        return articleRepository.findPage(query).getData();
    }

    private List<Order> generatorOrder(List<Order> orders) {
        if (null == orders) {
            orders = new ArrayList<>();
        }
        orders.add(new Order("featured", SqlKey.ASC));
        orders.add(new Order("weight", SqlKey.ASC));
        orders.add(new Order("group", SqlKey.ASC));
        orders.add(new Order("groupIndex", SqlKey.ASC));
        orders.add(new Order("createTime", SqlKey.DESC));
        return orders;
    }

    /**
     * 计算发布文章数量
     */
    public int countPostsByUser(SysUserDTO user) {
        String sql = "select count(1) from blog_article where create_by=? and status=? and open=?";
        return jdbcTemplate.queryForObject(sql, Integer.class, new Object[]{user.getUserId(), StatusType.NORMAL.getCode(), StatusType.NORMAL.getCode()});
    }

    /**
     * 计算被关注人数量
     */
    public int countWatcherByUser(SysUserDTO user) {
        String sql = "select count(1) from blog_user_watch where watched=?";
        return jdbcTemplate.queryForObject(sql, Integer.class, new Object[]{user.getUserId()});
    }

    /**
     * 计算关注人数量
     */
    public int countWatchedByUser(SysUserDTO user) {
        String sql = "select count(1) from blog_user_watch where watcher=?";
        return jdbcTemplate.queryForObject(sql, Integer.class, new Object[]{user.getUserId()});
    }

    /**
     * 查询关注人清单
     */
    public List<Long> findWatchedByUser(SysUserDTO user) {
        String sql = "select watched from blog_user_watch where watcher=?";
        return jdbcTemplate.queryForList(sql, Long.class, new Object[]{user.getUserId()});
    }

    /**
     * 判断文章是否已收藏
     */
    public boolean checkFavored(SysUserDTO user, Long articleId) {
        String sql = "select count(1) from blog_user_favor where user_id=? and article_id=?";
        int count = jdbcTemplate.queryForObject(sql, Integer.class, new Object[]{user.getUserId(), articleId});
        return count > 0 ? true : false;
    }

    /**
     * 判断用户是否已关注
     */
    public boolean checkWatched(SysUserDTO user, Long articleUserId) {
        String sql = "select count(1) from blog_user_watch where watcher=? and watched=?";
        int count = jdbcTemplate.queryForObject(sql, Integer.class, new Object[]{user.getUserId(), articleUserId});
        return count > 0 ? true : false;
    }

    /**
     * 文章发布事件
     */
    public void publicMessage(String entity) {
        try {
            Article article = JsonUtil.toBean(entity, Article.class);
            TbSysUser creator = tbSysUserService.findById(Convert.toLong(article.getCreateBy()));
            // 获取所有关注用户
            String sql = "select watcher from watch_user where watched=?";
            List<Long> userIds = jdbcTemplate.queryForList(sql, Long.class, new Object[]{creator.getUserId()});
            // 给用户发送消息通知
            if (null != userIds) {
                String title = "你关注的博主【" + creator.getUserName() + "】发表了一篇新文章 --- " + article.getTitle();
                mongoMessageService.insertWithUsers(userIds, title, OptionType.MESSAGE.getCode(),
                        "Article", "articleId=" + article.getArticleId(), "", null);
            }
        } catch (DataAccessException e) {
            log.error("文章发布事件异常：{}", e.getMessage());
        }
    }

    /**
     * 文章更新事件
     */
    public void updateMessage(String entity) {
        try {
            Article article = JsonUtil.toBean(entity, Article.class);
            // 获取所有收藏该文章的用户
            String sql = "select user_id from blog_user_favor where article_id=?";
            List<Long> userIds = jdbcTemplate.queryForList(sql, Long.class, new Object[]{article.getArticleId()});
            // 给用户发送消息通知
            if (null != userIds) {
                String title = "你收藏的文章【" + article.getTitle() + "】更新了！";
                mongoMessageService.insertWithUsers(userIds, title, OptionType.MESSAGE.getCode(),
                        "Article", "articleId=" + article.getArticleId(), "", null);
            }
        } catch (DataAccessException e) {
            log.error("文章更新事件异常：{}", e.getMessage());
        }
    }

    /**
     * 文章删除事件
     */
    public void deleteMessage(String entity) {
        try {
            Article article = JsonUtil.toBean(entity, Article.class);
            String sql = "delete from blog_user_favor where article_id=?";
            jdbcTemplate.update(sql, new Object[]{article.getArticleId()});
        } catch (DataAccessException e) {
            log.error("删除文章事件异常：{}", e.getMessage());
        }
    }

    /**
     * 文章收藏事件
     */
    public void favorMessage(String entity) {
        try {
            Article article = JsonUtil.toBean(entity, Article.class);
            SysUserDTO watcher = article.getUser();
            String title = "恭喜！你的文章【" + article.getTitle() + "】被【" + watcher.getUserName() + "】关注了！";
            List<Long> userIds = new ArrayList<>();
            userIds.add(Convert.toLong(article.getCreateBy()));
            MongoMessage message = new MongoMessage();
            message.setTitle(title);
            message.setType(OptionType.MESSAGE.getCode());
            message.setRouter("Article");
            message.setQuery("articleId=" + article.getArticleId());
            message.setReceiver(article.getCreateBy());
            mongoMessageService.insert(message);
        } catch (Exception e) {
            log.error("收藏文章异常：{}", e.getMessage());
        }
    }

    /**
     * 文章评论事件
     */
    public void commonMessage(String entity) {
        try {
            Article article = JsonUtil.toBean(entity, Article.class);
            article.setComments(article.getComments() + 1);
            update(article);
            String title = "你的文章【" + article.getTitle() + "】收到了新评论！";
            List<Long> userIds = new ArrayList<>();
            userIds.add(Convert.toLong(article.getCreateBy()));
            MongoMessage message = new MongoMessage();
            message.setTitle(title);
            message.setType(OptionType.MESSAGE.getCode());
            message.setRouter("Article");
            message.setQuery("articleId=" + article.getArticleId());
            message.setReceiver(article.getCreateBy());
            mongoMessageService.insert(message);
        } catch (Exception e) {
            log.error("评论文章异常：{}", e.getMessage());
        }
    }

    /**
     * 增加文章评论数量
     */
    public void addCommon(String entity) {
        try {
            Article article = JsonUtil.toBean(entity, Article.class);
            article.setComments(article.getComments() + 1);
            update(article);
        } catch (Exception e) {
            log.error("评论文章异常：{}", e.getMessage());
        }
    }

    /**
     * 文章阅读事件
     */
    public void viewMessage(String entity) {
        Article article = JsonUtil.toBean(entity, Article.class);
        article.setViews(article.getViews() + 1);
        try {
            update(article);
        } catch (Exception e) {
            log.error("文章阅读记录异常：{}", e.getMessage());
        }
    }

    /**
     * 重建文章索引数据
     */
    public List<Article> articleIndex() {
        String sql = "select a.article_id articleId, a.channel channel, a.title title, a.summary summary, a.thumbnail thumbnail, a.tags tags, a.favors favors," +
                " a.comments comments, a.views views, a.featured featured, a.weight weight, a.create_by createBy, a.create_time createTime, i.content content" +
                " from blog_article a, blog_article_info i where a.status = '0' and a.open = '0' and a.article_id = i.article_id";
        return jdbcTemplate.query(sql, (rs, i) -> {
            Article article = new Article();
            article.setArticleId(rs.getLong(1));
            article.setChannel(rs.getString(2));
            article.setTitle(rs.getString(3));
            article.setSummary(rs.getString(4));
            article.setThumbnail(rs.getString(5));
            article.setTags(rs.getString(6));
            article.setFavors(rs.getInt(7));
            article.setComments(rs.getInt(8));
            article.setViews(rs.getInt(9));
            article.setFeatured(rs.getString(10));
            article.setWeight(rs.getInt(11));
            article.setCreateBy(rs.getString(12));
            article.setCreateTime(rs.getDate(13));
            article.setContent(rs.getString(14));
            return article;
        });
    }
}
